home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / ULARN.ARJ / ULARN.TAR / ularn / monster.c < prev    next >
C/C++ Source or Header  |  1989-10-25  |  47KB  |  2,117 lines

  1. /*
  2.  *    monster.c
  3.  *
  4.  *    This file contains the following functions:
  5.  *    ------------------------------------------------------------------------
  6.  *
  7.  *    createmonster(monstno)    Function to create a monster next to the player
  8.  *        int monstno;
  9.  *
  10.  *    int cgood(x,y,itm,monst)    Function to check location for emptiness
  11.  *        int x,y,itm,monst;
  12.  *
  13.  *    createitem(it,arg)     Routine to place an item next to the player
  14.  *        int it,arg;
  15.  *
  16.  *    cast()         Subroutine called by parse to cast a spell for the user
  17.  *
  18.  *    speldamage(x)     Function to perform spell functions cast by the player
  19.  *        int x;
  20.  *
  21.  *    loseint()    Routine to decrement your int (intelligence) if > 3
  22.  *
  23.  *    isconfuse()     Routine to check to see if player is confused
  24.  *
  25.  *    nospell(x,monst) Routine to return 1 if a spell doesn't affect a monster
  26.  *        int x,monst;
  27.  *
  28.  *    fullhit(xx)    Function to return full damage against a monst (aka web)
  29.  *        int xx;
  30.  *
  31.  *            Routine to direct spell damage 1 square in 1 dir
  32.  *    direct(spnum,dam,str,arg)    
  33.  *        int spnum,dam,arg;
  34.  *        char *str;
  35.  *
  36.  *            Function to perform missile attacks
  37.  *    godirect(spnum,dam,str,delay,cshow)        
  38.  *        int spnum,dam,delay;
  39.  *        char *str,cshow;
  40.  *
  41.  *          Routine to put "monster" or the monster name into lastmosnt
  42.  *    ifblind(x,y)    
  43.  *        int x,y;
  44.  *
  45.  *    tdirect(spnum)        Routine to teleport away a monster
  46.  *        int spnum;
  47.  *
  48.  *              Routine to damage all monsters 1 square from player
  49.  *    omnidirect(sp,dam,str)  
  50.  *        int sp,dam;
  51.  *        char *str;
  52.  *
  53.  *    dirsub(x,y)    Routine to ask for direction, then modify x,y for it
  54.  *    int *x,*y;
  55.  *
  56.  *    vxy(x,y)      Routine to verify/fix (*x,*y) for being within bounds
  57.  *        int *x,*y;
  58.  *
  59.  *    dirpoly(spnum)    Routine to ask for a direction and polymorph a monst
  60.  *        int spnum;
  61.  *
  62.  *    hitmonster(x,y) Function to hit a monster at the designated coordinates
  63.  *        int x,y;
  64.  *
  65.  *    hitm(x,y,amt)    Function to just hit a monster at a given coordinates
  66.  *        int x,y,amt;
  67.  *
  68.  *    hitplayer(x,y)     Function for the monster to hit the player from (x,y)
  69.  *        int x,y;
  70.  *
  71.  *    dropsomething(monst)     Function to create an object when a monster dies
  72.  *        int monst;
  73.  *
  74.  *    dropgold(amount)    Function to drop some gold around player
  75.  *        int amount;
  76.  *
  77.  *    something(level)     Function to create a random item around player
  78.  *        int level;
  79.  *
  80.  *    newobject(lev,i)     Routine to return a randomly selected new object
  81.  *        int lev,*i;
  82.  *
  83.  *  spattack(atckno,xx,yy)    Function to process special attacks from monsters
  84.  *      int atckno,xx,yy;
  85.  *
  86.  *           Routine to subtract hp from user and flag bottomline display
  87.  *    checkloss(x)     
  88.  *        int x;
  89.  *
  90.  *           Routine to annihilate monsters around player, playerx,playery
  91.  *    annihilate()   
  92.  *
  93.  *          Function to create a new sphere of annihilation
  94.  *    newsphere(x,y,dir,lifetime)  
  95.  *        int x,y,dir,lifetime;
  96.  *
  97.  *    rmsphere(x,y)    Function to delete a sphere of annihilation from list
  98.  *        int x,y;
  99.  *
  100.  *    sphboom(x,y)    Function to perform the effects of a sphere detonation
  101.  *        int x,y;
  102.  *
  103.  *    genmonst()    Function to ask for monster and genocide from game
  104.  *
  105.  */
  106. #include "header.h"
  107.  
  108. struct isave    /* used for altar reality */
  109. {
  110.     char type;    /* 0=item,  1=monster */
  111.     char id;    /* item number or monster number */
  112.     short arg;    /* the type of item or hitpoints of monster */
  113. };
  114.  
  115. /*
  116.  *        Function to create a monster next to the player
  117.  *    createmonster(monstno)         
  118.  *        int monstno;
  119.  *
  120.  *    Enter with the monster number (1 to MAXMONST+8)
  121.  *    Returns no value.
  122.  */
  123. createmonster(mon)
  124. int mon;
  125. {
  126.     register int x,y,k,i;
  127.     if (mon<1 || mon>MAXMONST+8)    {
  128.         beep(); 
  129.         lprintf("\ncan't createmonst(%d)\n",(long)mon); 
  130.         nap(3000); 
  131.         return;
  132.     }
  133.     while (monster[mon].genocided && mon<MAXMONST) 
  134.         mon++; /* genocided? */
  135.     for (k=rnd(8), i= -8; i<0; i++,k++)/* choose direction, then try all */
  136.     {
  137.         if (k>8) k=1;        /* wraparound the diroff arrays */
  138.         x = playerx + diroffx[k];        
  139.         y = playery + diroffy[k];
  140.         if (cgood(x,y,0,1))    /* if we can create here */
  141.         {
  142.             mitem[x][y] = mon;
  143.             hitp[x][y] = monster[mon].hitpoints;
  144.             stealth[x][y]=know[x][y]=0;
  145.             switch(mon) {
  146.             case ROTHE: 
  147.             case POLTERGEIST: 
  148.             case VAMPIRE:    
  149.                 stealth[x][y]=1;
  150.             };
  151.             return;
  152.         }
  153.     }
  154. }
  155.  
  156. /*
  157.  *    int cgood(x,y,itm,monst)    Function to check location for emptiness
  158.  *        int x,y,itm,monst;
  159.  *
  160.  *    Routine to return TRUE if a location does not have itm or monst there
  161.  *    returns FALSE (0) otherwise
  162.  *    Enter with itm or monst TRUE or FALSE if checking it
  163.  *    Example:  if itm==TRUE check for no item at this location
  164.  *              if monst==TRUE check for no monster at this location
  165.  *    This routine will return FALSE if at a wall or the dungeon exit on level 1
  166.  */
  167. cgood(x,y,itm,monst)
  168. register int x,y;
  169. int itm,monst;
  170. {
  171.     if ((y>=0) && (y<=MAXY-1) 
  172.         && (x>=0) && (x<=MAXX-1))         /* within bounds? */
  173.       if (item[x][y]!=OWALL)        /* can't make on walls */
  174.         if (itm==0 || (item[x][y]==0))    /* is it free of items? */
  175.         if (monst==0 || (mitem[x][y]==0)) /*is it free of monsters? */
  176.             if ((level!=1) || (x!=33) || (y!=MAXY-1)) 
  177.                 /* not exit to level 1 */
  178.                 return(1);
  179.     return(0);
  180. }
  181.  
  182. /*
  183.  *    createitem(it,arg)     Routine to place an item next to the player
  184.  *        int it,arg;
  185.  *
  186.  *    Enter with the item number and its argument (iven[], ivenarg[])
  187.  *    Returns no value, thus we don't know about createitem() failures.
  188.  */
  189. createitem(it,arg)
  190. int it;
  191. long arg;
  192. {
  193.     register int x,y,k,i;
  194.  
  195.     if (it >= MAXOBJ) 
  196.         return;    /* no such object */
  197.  
  198.     for (k=rnd(8), i= -8; i<0; i++,k++) { /* choose direction, try all */
  199.         if (k>8) k=1;        /* wraparound the diroff arrays */
  200.         x = playerx + diroffx[k];
  201.         y = playery + diroffy[k];
  202.         if ( (it != OMAXGOLD && it != OGOLDPILE) ) {
  203.             if (cgood(x,y,1,0)) {    /* if we can create here */
  204.             item[x][y] = it;  
  205.             know[x][y]=0;  
  206.             iarg[x][y]=arg;  
  207.             return;
  208.             }
  209.         }
  210.         else {
  211.             int i;
  212.             switch (item[x][y]) {
  213.             case OGOLDPILE :
  214.                 if ( (iarg[x][y] + arg) < 32767) {
  215.                     iarg[x][y] += arg;
  216.                     return;
  217.                 }
  218.             case ODGOLD :
  219.                 if ( (10 * iarg[x][y] + arg) < 327670L) {
  220.                     i = iarg[x][y] ;
  221.                     iarg[x][y] = (10 * i + arg) / 10;
  222.                     item[x][y] = ODGOLD;
  223.                     return;
  224.                 }
  225.             case OMAXGOLD :
  226.                 if ( (100 * iarg[x][y] + arg) < 3276700L) {
  227.                     i = (100 * iarg[x][y]) + arg;
  228.                     iarg[x][y] = i / 100;
  229.                     item[x][y] = OMAXGOLD;
  230.                     return;
  231.                 }
  232.             case OKGOLD :
  233.                 if ( (1000 * iarg[x][y] + arg) < 32767000L) { 
  234.                     i = iarg[x][y];
  235.                     iarg[x][y] = (1000 * i + arg) / 1000;
  236.                     item[x][y] = OKGOLD;
  237.                     return;
  238.                 }
  239.                 else iarg[x][y] = 32767000L; 
  240.                 return;
  241.             default :
  242.                     if (cgood(x,y,1,0)) {
  243.                     item[x][y] = it;  
  244.                     know[x][y]=0;  
  245.                     if (it == OMAXGOLD)
  246.                         iarg[x][y]= arg / 100;  
  247.                     else iarg[x][y]=arg;  
  248.                     return;
  249.                 }
  250.             } /* end switch */
  251.         } /* end else */
  252.     } /* end for */
  253. }
  254.  
  255. /*
  256.  *    cast()         Subroutine called by parse to cast a spell for the user
  257.  *
  258.  *    No arguments and no return value.
  259.  */
  260. static char eys[] = "\nEnter your spell: ";
  261.  
  262. cast()
  263. {
  264.     register int i,j,a,b,d;
  265.  
  266.     cursors();
  267.     if (c[SPELLS]<=0) {    
  268.         lprcat("\nYou don't have any spells!");    
  269.         return;    
  270.     }
  271.     lprcat(eys);        
  272.     --c[SPELLS];
  273.     while ((a=getcharacter())=='D') {     
  274.         seemagic(-1); 
  275.         cursors();  
  276.         lprcat(eys); 
  277.     }
  278.     if (a=='\33') goto over;     /* to escape casting a spell    */
  279.     if ((b=getcharacter())=='\33') goto over; /*to escape casting a spell */
  280.     if ((d=getcharacter())=='\33') { 
  281. over: 
  282.         lprcat(aborted); 
  283.         c[SPELLS]++; 
  284.         return; 
  285.     }             /* to escape casting a spell */
  286.     /*seq search for his spell, hash?*/
  287.     for (lprc('\n'),j= -1,i=0; i<SPNUM+1; i++) 
  288.         if ((spelcode[i][0]==a) && (spelcode[i][1]==b) && (spelcode[i][2]==d))
  289.             if (spelknow[i]) {      
  290.                 speldamage(i);  
  291.                 j = 1;  
  292.                 i=SPNUM+1;
  293.             }
  294.  
  295.     if (j == -1) lprcat("  Nothing Happened ");
  296.     bottomline();
  297. }
  298.  
  299. /*
  300.  *    speldamage(x)    Function to perform spell functions cast by the player
  301.  *    int x;
  302.  *
  303.  *    Enter with the spell number, returns no value.
  304.  *    Please insure that there are 2 spaces before all messages here
  305.  */
  306. speldamage(x)
  307. int x;
  308. {
  309.     register int i,j,clev;
  310.     int xl,xh,yl,yh;
  311.     register char *p,*kn,*pm;
  312.  
  313.     if (x>=SPNUM+1) return;    /* no such spell */
  314.  
  315.     if (c[TIMESTOP])  {     
  316.         lprcat("  It didn't seem to work"); 
  317.         return; 
  318.     }  /* not if time stopped */
  319.  
  320.     if ((rnd(23)==7) || (rnd(18) > c[INTELLIGENCE]))
  321.     {     
  322.         lprcat("  It didn't work!");  
  323.         return; 
  324.     }
  325.  
  326.     clev = c[LEVEL];
  327.     if (clev*3+2 < x) 
  328.     {     
  329.         lprcat("  Nothing happens.  You seem inexperienced at this"); 
  330.         return; 
  331.     }
  332.  
  333.     switch(x)
  334.     {
  335.         /* ----- LEVEL 1 SPELLS ----- */
  336.  
  337.     case 0:    
  338.         if (c[PROTECTIONTIME]==0)
  339.             c[MOREDEFENSES]+=2; /* protection field +2 */
  340.         c[PROTECTIONTIME] += 250;   
  341.         return;
  342.  
  343.     case 1: 
  344.         i = rnd(((clev+1)<<1)) + clev + 3;
  345.         godirect(x,i,(clev>=2)?"  Your missiles hit the %s":"  Your missile hit the %s",100,'+'); /* magic missile */
  346.         return;
  347.  
  348.     case 2:    
  349.         if (c[DEXCOUNT]==0)    
  350.             c[DEXTERITY]+=3; /*    dexterity    */
  351.         c[DEXCOUNT] += 400;      
  352.         return;
  353.  
  354.     case 3: 
  355.         i=rnd(3)+1;
  356.         p="  While the %s slept, you smashed it %d times";
  357. ws:            
  358.         direct(x,fullhit(i),p,i); /*    sleep    */
  359.         return;
  360.  
  361.     case 4:    /* charm monster */
  362.  
  363.         c[CHARMCOUNT] += c[CHARISMA]<<1;    
  364.         return;
  365.  
  366.         /* sonic spear */
  367.     case 5:    
  368.         godirect(x,rnd(10)+15+clev,"  The sound damages the %s",70,'@'); 
  369.         return;
  370.  
  371.         /* ----- LEVEL 2 SPELLS ----- */
  372.  
  373.     case 6: 
  374.         i=rnd(3)+2;    
  375.         p="  While the %s is entangled, you hit %d times";
  376.         goto ws; /* web */
  377.  
  378.     case 7:    
  379.         if (c[STRCOUNT]==0) c[STREXTRA]+=3;/*    strength*/
  380.         c[STRCOUNT] += 150+rnd(100);    
  381.         return;
  382.  
  383.     case 8:    
  384.         yl = playery-5;     /* enlightenment */
  385.         yh = playery+6;   
  386.         xl = playerx-15;   
  387.         xh = playerx+16;
  388.         vxy(&xl,&yl);   
  389.         vxy(&xh,&yh); /* check bounds */
  390.         for (i=yl; i<=yh; i++) /* enlightenment    */
  391.             for (j=xl; j<=xh; j++)    know[j][i]=1;
  392.         draws(xl,xh+1,yl,yh+1);    
  393.         return;
  394.  
  395.     case 9:    
  396.         raisehp(20+(clev<<1));  
  397.         return;  /* healing */
  398.  
  399.     case 10:    
  400.         c[BLINDCOUNT]=0;    
  401.         return;    /* cure blindness    */
  402.  
  403.     case 11:    
  404.         createmonster(makemonst(level+1)+8);  
  405.         return;
  406.  
  407.     case 12: 
  408.         if (rnd(11)+7 <= c[WISDOM]) 
  409.             direct(x,rnd(20)+20+clev,"  The %s believed!",0);
  410.         else 
  411.             lprcat("  It didn't believe the illusions!");
  412.         return;
  413.  
  414.         /* if he has the amulet of invisibility then add more time */
  415.     case 13:    
  416.         for (j=i=0; i<26; i++)
  417.             if (iven[i]==OAMULET) 
  418.                 j+= 1+ivenarg[i];
  419.         c[INVISIBILITY] += (j<<7)+12;   
  420.         return;
  421.  
  422.         /* ----- LEVEL 3 SPELLS ----- */
  423.  
  424.     case 14:    
  425.         godirect(x,rnd(25+clev)+25+clev,"  The fireball hits the %s",40,'*'); 
  426.         return; /*    fireball */
  427.  
  428.     case 15:    
  429.         godirect(x,rnd(25)+20+clev,"  Your cone of cold strikes the %s",60,'O');    /*    cold */
  430.         return;
  431.  
  432.     case 16:    
  433.         dirpoly(x);  
  434.         return;    /*    polymorph */
  435.  
  436.     case 17:    
  437.         c[CANCELLATION]+= 5+clev;    
  438.         return;    /*    cancellation    */
  439.  
  440.     case 18:    
  441.         c[HASTESELF]+= 7+clev;  
  442.         return;  /*    haste self    */
  443.  
  444.         /* cloud kill */
  445.     case 19:    
  446.         omnidirect(x,30+rnd(10),"  The %s gasps for air");    
  447.         return;
  448.  
  449.         /* vaporize rock */
  450.     case 20:    
  451.         xh = min(playerx+1,MAXX-2);        
  452.         yh = min(playery+1,MAXY-2);
  453.         for (i=max(playerx-1,1); i<=xh; i++) 
  454.             for (j=max(playery-1,1); j<=yh; j++) {
  455.                 kn = &know[i][j];    
  456.                 pm = &mitem[i][j];
  457.                 switch(*(p= &item[i][j])) {
  458.                 case OWALL: 
  459.                     if (level<MAXLEVEL+MAXVLEVEL-3)
  460.                         *p = *kn = 0;
  461.                     break;
  462.  
  463.                 case OSTATUE:
  464.                     if (c[HARDGAME]>3 && rnd(60)<30)
  465.                         break;
  466.                     *p=OBOOK; 
  467.                     iarg[i][j]=level;  
  468.                     *kn=0;
  469.                     break;
  470.  
  471.                 case OTHRONE: 
  472.                     *pm=GNOMEKING;  
  473.                     *kn=0;  
  474.                     *p= OTHRONE2;
  475.                     hitp[i][j]=monster[GNOMEKING].hitpoints; 
  476.                     break;
  477.  
  478.                 case OALTAR:    
  479.                     *pm=DEMONPRINCE;  
  480.                     *kn=0;
  481.                     hitp[i][j]=monster[DEMONPRINCE].hitpoints; 
  482.                     createmonster(DEMONPRINCE);
  483.                     createmonster(DEMONPRINCE);
  484.                     createmonster(DEMONPRINCE);
  485.                     createmonster(DEMONPRINCE);
  486.                     break;
  487.                 };
  488.                 switch(*pm)
  489.                 {    /* Xorn takes damage from vpr */
  490.                 case XORN:    
  491.                     ifblind(i,j);  
  492.                     hitm(i,j,200); 
  493.                     break; 
  494.                 case TROLL:
  495.                     ifblind(i,j);  
  496.                     hitm(i,j,200); 
  497.                     break; 
  498.                 }
  499.             }
  500.         return;
  501.  
  502.         /* ----- LEVEL 4 SPELLS ----- */
  503.  
  504.     case 21:/* dehydration */
  505.  
  506.         direct(x,100+clev,"  The %s shrivels up",0); 
  507.         return;
  508.  
  509.     case 22:    /*    lightning */
  510.         godirect(x,rnd(25)+20+(clev<<1),"  A lightning bolt hits the %s",1,'~');    
  511.         return;
  512.  
  513.     case 23:    
  514.         i=min(c[HP]-1,c[HPMAX]/2);    /* drain life */
  515.         direct(x,i+i,"",0);    
  516.         c[HP] -= i;      
  517.         return;
  518.  
  519.     case 24:    
  520.         if (c[GLOBE]==0) c[MOREDEFENSES] += 10;
  521.         c[GLOBE] += 200;  
  522.         loseint();  /* globe of invulnerability */
  523.         return;
  524.  
  525.     case 25:    
  526.         omnidirect(x,32+clev,"  The %s struggles for air in your flood!"); /* flood */
  527.         return;
  528.  
  529.         /* finger of death */
  530.     case 26:    
  531.         if (rnd(151)==63) { 
  532.             beep(); 
  533.             lprcat("\nYour heart stopped!\n"); 
  534.             nap(4000);  
  535.             died(270); 
  536.             return; 
  537.         }
  538.         if (c[WISDOM]>rnd(10)+10) direct(x,2000,"  The %s's heart stopped",0); 
  539.         else lprcat("  It didn't work"); 
  540.         return;
  541.  
  542.         /* ----- LEVEL 5 SPELLS ----- */
  543.  
  544.         /* scare monster */
  545.     case 27:    
  546.         c[SCAREMONST] += rnd(10)+clev;
  547.  
  548.         /* if have HANDofFEAR make last longer */
  549.         for (j=i=0; i<26; i++)
  550.             if (iven[i]==OHANDofFEAR) {
  551.                 c[SCAREMONST] *= 3;
  552.                 break;
  553.             }
  554.         return;
  555.  
  556.     case 28:    
  557.         c[HOLDMONST] += rnd(10)+clev;  
  558.         return;  /* hold monster */
  559.  
  560.     case 29:    
  561.         c[TIMESTOP] += rnd(20)+(clev<<1);  
  562.         return;  /* time stop */
  563.  
  564.     case 30:    
  565.         tdirect(x);  
  566.         return;  /* teleport away */
  567.  
  568.         /* magic fire */
  569.     case 31:    
  570.         omnidirect(x,35+rnd(10)+clev,"  The %s cringes from the flame"); 
  571.         return;
  572.  
  573.         /* ----- LEVEL 6 SPELLS ----- */
  574.  
  575.     case 32:    /* make wall */
  576.         makewall(x);
  577.         return;
  578.  
  579.         /* sphere of annihilation */
  580.     case 33:    
  581.         if ((rnd(23)==5) && (wizard==0)) 
  582.         {     
  583.             beep(); 
  584.             lprcat("\nYou have been enveloped by the zone of nothingness!\n");
  585.             nap(4000);  
  586.             died(258); 
  587.             return;
  588.         }
  589.         xl=playerx; 
  590.         yl=playery;
  591.         loseint();
  592.         i=dirsub(&xl,&yl); /* get direction of sphere */
  593.         newsphere(xl,yl,i,rnd(20)+11);/*make a sphere */
  594.         return;
  595.  
  596.     case 34:    
  597.         genmonst();  
  598.         spelknow[34]=0;  /* genocide */
  599.         loseint();
  600.         return;
  601.  
  602.     case 35:/* summon demon */
  603.         if (rnd(100) > 30) { 
  604.             direct(x-1,150,"  The demon strikes at the %s",0);  
  605.             return; 
  606.         }
  607.         if (rnd(100) > 15) { 
  608.             lprcat("  Nothing seems to have happened");  
  609.             return; 
  610.         }
  611.         lprcat("  The demon turned on you and vanished!"); 
  612.         beep();
  613.         i=rnd(40)+30;  
  614.         lastnum=277;
  615.         losehp(i); /* must say killed by a demon */
  616.  
  617.         return;
  618.  
  619.     case 36:/* walk through walls */
  620.         c[WTW] += rnd(10)+5;    
  621.         return;
  622.  
  623.     case 37:/* alter reality */
  624.         {
  625.             struct isave *save;    
  626.             /* pointer to item save structure */
  627.             int sc;    
  628.             sc=0;    /* # items saved */
  629.             save = (struct isave *)malloc(sizeof(struct isave)*MAXX*MAXY*2);
  630.             for (j=0; j<MAXY; j++)/* save all items and monsters */
  631.                 for (i=0; i<MAXX; i++)
  632.                 {
  633.                     xl = item[i][j];
  634.                     if (xl && xl!=OWALL && xl!=OANNIHILATION) 
  635.                     {
  636.                         save[sc].type=0;  
  637.                         save[sc].id=item[i][j];
  638.                         save[sc++].arg=iarg[i][j];
  639.                     }
  640.                     if (mitem[i][j]) 
  641.                     {
  642.                         save[sc].type=1;  
  643.                         save[sc].id=mitem[i][j];
  644.                         save[sc++].arg=hitp[i][j];
  645.                     }
  646.                     item[i][j]=OWALL;   
  647.                     mitem[i][j]=0;
  648.                     if (wizard) know[i][j]=1; 
  649.                     else know[i][j]=0;
  650.                 }
  651.             eat(1,1);    
  652.             if (level==1) item[33][MAXY-1]=0;
  653.             for (j=rnd(MAXY-2), i=1; i<MAXX-1; i++) item[i][j]=0;
  654.             while (sc>0) /* put objects back in level */
  655.             {
  656.                 --sc;
  657.                 if (save[sc].type == 0)
  658.                 {
  659.                     int trys;
  660.                     for (trys=100, i=j=1; --trys>0 && item[i][j]; i=rnd(MAXX-1), j=rnd(MAXY-1));
  661.                     if (trys) { 
  662.                         item[i][j]=save[sc].id; 
  663.                         iarg[i][j]=save[sc].arg; 
  664.                     }
  665.                 }
  666.                 else
  667.                 { /* put monsters back in */
  668.                     int trys;
  669.                     for (trys=100, i=j=1; --trys>0 && (item[i][j]==OWALL || mitem[i][j]); i=rnd(MAXX-1), j=rnd(MAXY-1));
  670.                     if (trys) { 
  671.                         mitem[i][j]=save[sc].id; 
  672.                         hitp[i][j]=save[sc].arg; 
  673.                     }
  674.                 }
  675.             }
  676.             loseint();
  677.             draws(0,MAXX,0,MAXY);  
  678.             if (wizard==0) spelknow[37]=0;
  679.             free((char*)save);     
  680.             positionplayer();  
  681.             return;
  682.         }
  683.  
  684.     case 38:    /* permanence */
  685.  
  686.         adjtime(-99999L);  
  687.         spelknow[38]=0; /* forget */
  688.         loseint();
  689.         return;
  690.  
  691.     default:    
  692.         lprintf("  spell %d not available!",(long)x); 
  693.         beep();  
  694.         return;
  695.     };
  696. }
  697.  
  698. /*
  699.  *    loseint()        
  700.  *        Routine to subtract 1 from your int (intelligence) if > 3
  701.  *
  702.  *    No arguments and no return value
  703.  */
  704. loseint()
  705. {
  706.     if (--c[INTELLIGENCE]<3)  c[INTELLIGENCE]=3;
  707. }
  708.  
  709. /*
  710.  *    isconfuse()         Routine to check to see if player is confused
  711.  *
  712.  *    This routine prints out a message saying "You can't aim your magic!"
  713.  *    returns 0 if not confused, non-zero (time remaining confused) 
  714.  *    if confused
  715.  */
  716. isconfuse()
  717. {
  718.     if (c[CONFUSE]) { 
  719.         lprcat(" You can't aim your magic!"); 
  720.         beep(); 
  721.     }
  722.     return(c[CONFUSE]);
  723. }
  724.  
  725. /*        Routine to return 1 if a spell doesn't affect a monster
  726.  *    nospell(x,monst)    
  727.  *    int x,monst;
  728.  *
  729.  *    Subroutine to return 1 if the spell can't affect the monster
  730.  *      otherwise returns 0
  731.  *    Enter with the spell number in x, and the monster number in monst.
  732.  */
  733. nospell(x,monst)
  734. int x,monst;
  735. {
  736.     register int tmp;
  737.  
  738.     /* bad spell or monst */
  739.     if (x>=SPNUM || monst>MAXMONST+8 || monst<0 || x<0) return(0);    
  740.  
  741.     if ((tmp=spelweird[monst-1][x])==0) 
  742.         return(0);
  743.     cursors();  
  744.     lprc('\n');  
  745.     lprintf(spelmes[tmp],monster[monst].name);  
  746.     return(1);
  747. }
  748.  
  749. /*
  750.  *        Function to return full damage against a monster (aka web)
  751.  *    fullhit(xx)        
  752.  *        int xx;
  753.  *
  754.  *    Function to return hp damage to monster due to a number of full hits
  755.  *    Enter with the number of full hits being done
  756.  */
  757. fullhit(xx)
  758. int xx;
  759. {
  760.     register int i;
  761.  
  762.     if (xx<0 || xx>20) return(0);    /* fullhits are out of range */
  763.     if (c[LANCEDEATH]) return(10000);    /* lance of death */
  764.  
  765. i = xx * ((c[WCLASS]>>1)+c[STRENGTH]+c[STREXTRA]-c[HARDGAME]-12+c[MOREDAM]); 
  766.  
  767.     return( (i>=1) ? i : xx );
  768. }
  769.  
  770. /*
  771.  *        Routine to direct spell damage 1 square in 1 dir
  772.  *    direct(spnum,dam,str,arg)    
  773.  *    int spnum,dam,arg;
  774.  *    char *str;
  775.  *
  776.  *    Routine to ask for a direction to a spell and then hit the monster
  777.  *    Enter with the spell number in spnum, the damage to be done in dam,
  778.  *      lprintf format string in str, and lprintf's argument in arg.
  779.  *    Returns no value.
  780.  */
  781. direct(spnum,dam,str,arg)
  782. int spnum,dam,arg;
  783. char *str;
  784. {
  785.     int x,y;
  786.     register int m;
  787.     if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad arguments */
  788.     if (isconfuse()) return;
  789.     dirsub(&x,&y);
  790.     m = mitem[x][y];
  791.     if (item[x][y]==OMIRROR) {
  792.         if (spnum==3) /* sleep */
  793.         {
  794.             lprcat("You fall asleep! "); 
  795.             beep();
  796. fool:
  797.             arg += 2;
  798.             while (arg-- > 0) { 
  799.                 parse2(); 
  800.                 nap(1000); 
  801.             }
  802.             return;
  803.         }
  804.         else if (spnum==6) /* web */
  805.         {
  806.             lprcat("You get stuck in your own web! "); 
  807.             beep();
  808.             goto fool;
  809.         }
  810.         else {
  811.             lastnum=278; 
  812.             lprintf(str,"spell caster (thats you)",(long)arg);
  813.             beep(); 
  814.             losehp(dam); 
  815.             return;
  816.         }
  817.     }
  818.     if (m==0) {    
  819.         lprcat("  There wasn't anything there!");    
  820.         return;  
  821.     }
  822.     ifblind(x,y);
  823.     if (nospell(spnum,m)) { 
  824.         lasthx=x;  
  825.         lasthy=y; 
  826.         return; 
  827.     }
  828.     lprintf(str,lastmonst,(long)arg);       
  829.     hitm(x,y,dam);
  830. }
  831.  
  832. /*
  833.  *                Function to perform missile attacks
  834.  *    godirect(spnum,dam,str,delay,cshow)        
  835.  *        int spnum,dam,delay;
  836.  *        char *str,cshow;
  837.  *
  838.  *    Function to hit in a direction from a missile weapon and have it keep
  839.  *    on going in that direction until its power is exhausted
  840.  *    Enter with the spell number in spnum, the power of the weapon in hp,
  841.  *      lprintf format string in str, the # of milliseconds to delay between 
  842.  *     locations in delay, and the character to represent the weapon in cshow.
  843.  *    Returns no value.
  844.  */
  845. godirect(spnum,dam,str,delay,cshow)
  846. int spnum,dam,delay;
  847. char *str,cshow;
  848. {
  849.     register char *p;
  850.     register int x,y,m;
  851.     int dx,dy;
  852.  
  853.     if (spnum<0 || spnum>=SPNUM || str==0 || delay<0) return; /* bad args */
  854.  
  855.     if (isconfuse()) return;
  856.  
  857.     dirsub(&dx,&dy);    
  858.     x=dx;    
  859.     y=dy;
  860.     dx = x-playerx;        
  861.     dy = y-playery;        
  862.     x = playerx;    
  863.     y = playery;
  864.  
  865.     while (dam>0) {
  866.         x += dx;    
  867.         y += dy;
  868.         if ((x > MAXX-1) || (y > MAXY-1) || (x < 0) || (y < 0)) {
  869.             dam=0;    
  870.             break;  /* out of bounds */
  871.         }
  872.         if ((x==playerx) && (y==playery)) /* if energy hits player */
  873.         {
  874.             cursors(); 
  875.             lprcat("\nYou are hit my your own magic!"); 
  876.             beep();
  877.             lastnum=278;  
  878.             losehp(dam);  
  879.             return;
  880.         }
  881.         if (c[BLINDCOUNT]==0) /* if not blind show effect */
  882.         {
  883.             cursor(x+1,y+1); 
  884.             lprc(cshow); 
  885.             nap(delay); 
  886.             show1cell(x,y);
  887.         }
  888.         if ((m=mitem[x][y]))    /* is there a monster there? */
  889.         {
  890.             ifblind(x,y);
  891.             if (m == LUCIFER || (m>=DEMONLORD && rnd(100)<10) ) {
  892.                 dx *= -1;    
  893.                 dy *= -1;    
  894.                 cursors();
  895.                 lprc('\n');
  896.                 lprintf("\nthe %s returns your puny missile!", monster[m].name);
  897.             } 
  898.             else {
  899.                 if (nospell(spnum,m)) { 
  900.                     lasthx=x;  
  901.                     lasthy=y; 
  902.                     return; 
  903.                 }
  904.                 cursors(); 
  905.                 lprc('\n');
  906.                 lprintf(str,lastmonst);        
  907.                 dam -= hitm(x,y,dam);
  908.                 show1cell(x,y);  
  909.                 nap(1000);
  910.                 x -= dx;
  911.                 y -= dy;
  912.             }
  913.         }
  914.         else switch (*(p= &item[x][y])) {
  915.         case OWALL:    
  916.             cursors(); 
  917.             lprc('\n'); 
  918.             lprintf(str,"wall");
  919.             if (dam>=50+c[HARDGAME]) /* enough damage? */
  920.                 if (level<MAXLEVEL+MAXVLEVEL-3) /* not on V3 */
  921.                     if ((x<MAXX-1) && (y<MAXY-1) && (x) && (y))
  922.                     {
  923.                         lprcat("  The wall crumbles");
  924. god3:    
  925.                         *p=0;
  926. god:    
  927.                         know[x][y]=0;
  928.                         show1cell(x,y);
  929.                     }
  930. god2:    
  931.             dam = 0;    
  932.             break;
  933.  
  934.         case OCLOSEDDOOR:    
  935.             cursors(); 
  936.             lprc('\n'); 
  937.             lprintf(str,"door");
  938.             if (dam>=40) {
  939.                 lprcat("  The door is blasted apart");
  940.                 goto god3;
  941.             }
  942.             goto god2;
  943.  
  944.         case OSTATUE:    
  945.             cursors(); 
  946.             lprc('\n'); 
  947.             lprintf(str,"statue");
  948.             if (dam>44) {
  949.                 if (c[HARDGAME] > 3 && rnd(60)<30)
  950.                     goto god2;
  951.                 lprcat("  The statue crumbles");
  952.                 *p=OBOOK; 
  953.                 iarg[x][y]=level;
  954.                 goto god;
  955.             }
  956.             goto god2;
  957.  
  958.         case OTHRONE:    
  959.             cursors(); 
  960.             lprc('\n'); 
  961.             lprintf(str,"throne");
  962.             if (dam>33) {
  963.                 mitem[x][y]=GNOMEKING; 
  964.                 hitp[x][y]=monster[GNOMEKING].hitpoints;
  965.                 *p = OTHRONE2;
  966.                 goto god;
  967.             }
  968.             goto god2;
  969.  
  970.         case OMIRROR:
  971.             dx *= -1;    
  972.             dy *= -1;    
  973.             break;
  974.         };
  975.         dam -= 3 + (c[HARDGAME]>>1);
  976.     }
  977. }
  978.  
  979. /*
  980.  *        Routine to put "monster" or the monster name into lastmosnt
  981.  *    ifblind(x,y)    
  982.  *    int x,y;
  983.  *
  984.  *    Subroutine to copy the word "monster" into lastmonst if the player is 
  985.  *     blind. Enter with the coordinates (x,y) of the monster
  986.  *    Returns no value.
  987.  */
  988. ifblind(x,y)
  989. int x,y;
  990. {
  991.     char *p;
  992.     vxy(&x,&y);    /* verify correct x,y coordinates */
  993.     if (c[BLINDCOUNT]) { 
  994.         lastnum=279;  
  995.         p="monster"; 
  996.     }
  997.     else { 
  998.         lastnum=mitem[x][y];  
  999.         p=monster[lastnum].name; 
  1000.     }
  1001.     strcpy(lastmonst,p);
  1002. }
  1003.  
  1004. /*
  1005.  *    tdirect(spnum)        Routine to teleport away a monster
  1006.  *    int spnum;
  1007.  *
  1008.  *    Routine to ask for a direction to a spell and then teleport away monster
  1009.  *    Enter with the spell number that wants to teleport away
  1010.  *    Returns no value.
  1011.  */
  1012. tdirect(spnum)
  1013. int spnum;
  1014. {
  1015.     int x,y;
  1016.     register int m;
  1017.  
  1018.     if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  1019.     if (isconfuse()) return;
  1020.     dirsub(&x,&y);
  1021.     if ((m=mitem[x][y])==0)
  1022.     {    
  1023.         lprcat("  There wasn't anything there!");    
  1024.         return;  
  1025.     }
  1026.     ifblind(x,y);
  1027.     if (nospell(spnum,m)) { 
  1028.         lasthx=x;  
  1029.         lasthy=y; 
  1030.         return; 
  1031.     }
  1032.     fillmonst(m);  
  1033.     mitem[x][y]=know[x][y]=0;
  1034. }
  1035.  
  1036.  
  1037. makewall(spnum)
  1038. int spnum;
  1039. {
  1040.     int x,y;
  1041.  
  1042.     if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  1043.     if (isconfuse()) return;
  1044.     dirsub(&x,&y);
  1045.  
  1046.     if ((y>=0) && (y<=MAXY-1) && (x>=0) && (x<=MAXX-1)) /* within bounds? */
  1047.         if (item[x][y]!=OWALL) {    /* can't make anything on walls */
  1048.             if (item[x][y]==0){    /* is it free of items? */
  1049.                 if (mitem[x][y]==0){  /*is it free of monsters? */
  1050.                     if ((level!=1) || (x!=33) || (y!=MAXY-1)) {
  1051.                         item[x][y]=OWALL;
  1052.                         know[x][y]=1;
  1053.                         show1cell(x,y);
  1054.                     }
  1055.                     else lprcat("\nyou can't make a wall there!");
  1056.                 }
  1057.                 else lprcat("\nthere's a monster there!");
  1058.             }
  1059.             else lprcat("\nthere's something there already!");
  1060.         }
  1061.         else lprcat("\nthere's a wall there already!");
  1062.  
  1063. }
  1064.  
  1065. /*
  1066.  *    omnidirect(sp,dam,str)   Routine to damage all monsters 1 square from player
  1067.  *        int sp,dam;
  1068.  *        char *str;
  1069.  *
  1070.  *    Routine to cast a spell and then hit the monster in all directions
  1071.  *    Enter with the spell number in sp, the damage done to wach square in dam,
  1072.  *      and the lprintf string to identify the spell in str.
  1073.  *    Returns no value.
  1074.  */
  1075. omnidirect(spnum,dam,str)
  1076. int spnum,dam;
  1077. char *str;
  1078. {
  1079.     register int x,y,m;
  1080.     if (spnum<0 || spnum>=SPNUM || str==0) return; /* bad args */
  1081.     for (x=playerx-1; x<playerx+2; x++)
  1082.         for (y=playery-1; y<playery+2; y++)
  1083.         {
  1084.             if (m=mitem[x][y])
  1085.                 if (nospell(spnum,m) == 0)
  1086.                 {
  1087.                     ifblind(x,y);
  1088.                     cursors(); 
  1089.                     lprc('\n'); 
  1090.                     lprintf(str,lastmonst);
  1091.                     hitm(x,y,dam);  
  1092.                     nap(800);
  1093.                 }
  1094.                 else  { 
  1095.                     lasthx=x;  
  1096.                     lasthy=y; 
  1097.                 }
  1098.         }
  1099. }
  1100.  
  1101. /*
  1102.  *        Routine to ask for direction, then modify x,y for it
  1103.  *    static dirsub(x,y)        
  1104.  *    int *x,*y;
  1105.  *
  1106.  *    Function to ask for a direction and modify an x,y for that direction
  1107.  *    Enter with the origination coordinates in (x,y).
  1108.  *    Returns index into diroffx[] (0-8).
  1109.  */
  1110. dirsub(x,y)
  1111. int *x,*y;
  1112. {
  1113.     register int i;
  1114.     lprcat("\nIn What Direction? ");
  1115.     for (i=0; ; )
  1116.         switch(getcharacter())
  1117.         {
  1118.         case 'b':    
  1119.             i++;
  1120.         case 'n':    
  1121.             i++;    
  1122.         case 'y':    
  1123.             i++;    
  1124.         case 'u':    
  1125.             i++;
  1126.         case 'h':    
  1127.             i++;    
  1128.         case 'k':    
  1129.             i++;
  1130.         case 'l':    
  1131.             i++;    
  1132.         case 'j':    
  1133.             i++;        
  1134.             goto out;
  1135.         };
  1136. out:
  1137.     *x = playerx+diroffx[i];        
  1138.     *y = playery+diroffy[i];
  1139.     vxy(x,y);  
  1140.     return(i);
  1141. }
  1142.  
  1143. /*
  1144.  *    vxy(x,y)       Routine to verify/fix coordinates for being within bounds
  1145.  *        int *x,*y;
  1146.  *
  1147.  *    Function to verify x & y are within the bounds for a level
  1148.  *    If *x or *y is not within the absolute bounds for a level, fix them so that
  1149.  *      they are on the level.
  1150.  *    Returns TRUE if it was out of bounds, and the *x & *y in the calling
  1151.  *    routine are affected.
  1152.  */
  1153. vxy(x,y)
  1154. int *x,*y;
  1155. {
  1156.     int flag=0;
  1157.     if (*x<0) { 
  1158.         *x=0; 
  1159.         flag++; 
  1160.     }
  1161.     if (*y<0) { 
  1162.         *y=0; 
  1163.         flag++; 
  1164.     }
  1165.     if (*x>=MAXX) { 
  1166.         *x=MAXX-1; 
  1167.         flag++; 
  1168.     }
  1169.     if (*y>=MAXY) { 
  1170.         *y=MAXY-1; 
  1171.         flag++; 
  1172.     }
  1173.     return(flag);
  1174. }
  1175.  
  1176. /*
  1177.  *    dirpoly(spnum)        Routine to ask for a direction and polymorph a monst
  1178.  *        int spnum;
  1179.  *
  1180.  *    Subroutine to polymorph a monster and ask for the direction its in
  1181.  *    Enter with the spell number in spmun.
  1182.  *    Returns no value.
  1183.  */
  1184. dirpoly(spnum)
  1185. int spnum;
  1186. {
  1187.     int x,y,m;
  1188.     if (spnum<0 || spnum>=SPNUM) return; /* bad args */
  1189.     if (isconfuse()) return;    /* if he is confused, he can't aim his magic */
  1190.     dirsub(&x,&y);
  1191.     if (mitem[x][y]==0)
  1192.     {    
  1193.         lprcat("  There wasn't anything there!");    
  1194.         return;  
  1195.     }
  1196.     ifblind(x,y);
  1197.     if (nospell(spnum,mitem[x][y])) { 
  1198.         lasthx=x;  
  1199.         lasthy=y; 
  1200.         return; 
  1201.     }
  1202.     while ( monster[m = mitem[x][y] = rnd(MAXMONST+7)].genocided );
  1203.     hitp[x][y] = monster[m].hitpoints;
  1204.     show1cell(x,y);  /* show the new monster */
  1205. }
  1206.  
  1207. /*
  1208.  *        Function to hit a monster at the designated coordinates
  1209.  *    hitmonster(x,y)     
  1210.  *    int x,y;
  1211.  *
  1212.  *    This routine is used for a bash & slash type attack on a monster
  1213.  *    Enter with the coordinates of the monster in (x,y).
  1214.  *    Returns no value.
  1215.  */
  1216. hitmonster(x,y)
  1217. int x,y;
  1218. {
  1219.     register int tmp,monst,damag,flag;
  1220.  
  1221.     if (c[TIMESTOP])  return;  /* not if time stopped */
  1222.  
  1223.     vxy(&x,&y);    /* verify coordinates are within range */
  1224.  
  1225.     if ((monst = mitem[x][y]) == 0) return;
  1226.  
  1227.     hit3flag=1;  
  1228.     ifblind(x,y);
  1229.  
  1230. tmp = monster[monst].armorclass + c[LEVEL] + c[DEXTERITY] + c[WCLASS/4] -12 
  1231.         - c[HARDGAME];
  1232.  
  1233.     cursors();
  1234.  
  1235.     /* need at least random chance to hit */
  1236.     if ((rnd(20) < tmp) || (rnd(71) < 5)) {     
  1237.         lprcat("\nYou hit");  
  1238.         flag=1;
  1239.         damag = fullhit(1);  
  1240.         if (damag<9999) damag=rnd(damag)+1;
  1241.     }
  1242.     else {     
  1243.         lprcat("\nYou missed");  
  1244.         flag=0;
  1245.     }
  1246.     lprcat(" the "); 
  1247.  
  1248.     lprcat(lastmonst);
  1249.     /*    lprintf(" (tmp = %d)", tmp); */
  1250.  
  1251.     if (flag)    /* if the monster was hit */
  1252.         if (iven[c[WIELD]] != OSWORDofSLASHING)
  1253.             if ((monst==RUSTMONSTER) || (monst==DISENCHANTRESS) || (monst==CUBE))
  1254.                 if (c[WIELD]>0)
  1255.                     if (ivenarg[c[WIELD]] > -10) {
  1256.                         lprintf("\nYour weapon is dulled by the %s",lastmonst); 
  1257.                         beep();
  1258.                         --ivenarg[c[WIELD]];
  1259.                     }
  1260.     if (flag) {
  1261.         hitm(x,y,damag);
  1262.         if ((monst >= DEMONLORD) && 
  1263.             (c[LANCEDEATH]) && 
  1264.             (hitp[x][y]) )
  1265.             lprintf("\nYour lance of death tickles the %s!",lastmonst);
  1266.     }
  1267. /*
  1268.     if (monst == VAMPIRE) 
  1269.         if (hitp[x][y]<25)
  1270.         {    mitem[x][y]=LEMMING; 
  1271.             know[x][y]=0; 
  1272.         }
  1273. */
  1274.  
  1275.     if (monst == METAMORPH)
  1276.         if (hitp[x][y]<25 && hitp[x][y] > 0)
  1277.             mitem[x][y]=BRONZEDRAGON+rund(9);
  1278.  
  1279.     if (mitem[x][y]==LEMMING)
  1280.         if (rnd(100)<=40) createmonster(LEMMING);
  1281. }
  1282.  
  1283. /*
  1284.  *        Function to just hit a monster at a given coordinates
  1285.  *    hitm(x,y,amt)
  1286.  *        int x,y,amt;
  1287.  *
  1288.  *    Returns the number of hitpoints the monster absorbed
  1289.  *This routine is used to specifically damage a monster at a location (x,y)
  1290.  *    Called by hitmonster(x,y)
  1291.  */
  1292. hitm(x,y,amt)
  1293. int x,y;
  1294. register amt;
  1295. {
  1296.     register int monst;
  1297.     int hpoints,amt2;
  1298.  
  1299.     vxy(&x,&y);    /* verify coordinates are within range */
  1300.     amt2 = amt;    /* save initial damage so we can return it */
  1301.     monst = mitem[x][y];
  1302.  
  1303.     /* if half damage curse adjust damage points */
  1304.     if (c[HALFDAM]) amt >>= 1;    
  1305.     if (amt<=0) amt2 = amt = 1;
  1306.  
  1307.     lasthx=x;
  1308.     lasthy=y;
  1309.  
  1310.     /* make sure hitting monst breaks stealth condition */
  1311.     stealth[x][y]=1;    
  1312.     c[HOLDMONST]=0;    /* hit a monster breaks hold monster spell    */
  1313.     switch(monst) /* if a dragon and orb(s) of dragon slaying    */
  1314.     {
  1315.     case WHITEDRAGON:
  1316.     case REDDRAGON:
  1317.     case GREENDRAGON:
  1318.     case BRONZEDRAGON:
  1319.     case PLATINUMDRAGON:
  1320.     case SILVERDRAGON:
  1321.         if (c[SLAYING])
  1322.             amt *= 3;
  1323.         break;
  1324.     }
  1325.     /* invincible monster fix is here */
  1326.     if (hitp[x][y] > monster[monst].hitpoints)
  1327.         hitp[x][y] = monster[monst].hitpoints;
  1328.  
  1329.     if (monst >= DEMONLORD) {
  1330.         if (c[LANCEDEATH]) 
  1331.             amt=300;
  1332.         if (iven[c[WIELD]] == OSLAYER)
  1333.             amt=10000;
  1334.     }
  1335.  
  1336.     if ((hpoints = hitp[x][y]) <= amt) {
  1337.         lprintf("\nThe %s died!",lastmonst);
  1338.         raiseexperience((long)monster[monst].experience);
  1339.         amt = monster[monst].gold;  
  1340.         if (amt>0) dropgold(rnd(amt)+amt);
  1341.         dropsomething(monst);    
  1342.         disappear(x,y);    
  1343.         bottomline();
  1344.         hitp[x][y] = 0;
  1345.         return(hpoints);
  1346.     }
  1347.     hitp[x][y] = hpoints-amt;    
  1348.     return(amt2);
  1349. }
  1350.  
  1351. /*
  1352.  *            Function for the monster to hit the player from (x,y)
  1353.  *    hitplayer(x,y)         
  1354.  *        int x,y;
  1355.  *
  1356.  *    Function for the monster to hit the player with monster at location x,y
  1357.  *    Returns nothing of value.
  1358.  */
  1359. hitplayer(x,y)
  1360. int x,y;
  1361. {
  1362.     register int dam,tmp,mster,bias;
  1363.  
  1364.     vxy(&x,&y);    /* verify coordinates are within range */
  1365.  
  1366.     lastnum = mster = mitem[x][y];
  1367.  
  1368.     if ((know[x][y]&1) == 0) {
  1369.         know[x][y]=1; 
  1370.         show1cell(x,y);
  1371.     }
  1372.  
  1373.     bias = (c[HARDGAME]) + 1;
  1374.     hitflag = hit2flag = hit3flag = 1;
  1375.     yrepcount=0;
  1376.     cursors();    
  1377.     ifblind(x,y);
  1378.  
  1379.     if (mster < DEMONLORD)
  1380.         if (c[INVISIBILITY]) if (rnd(33)<20) {
  1381.             lprintf("\nThe %s misses wildly",lastmonst);    
  1382.             return;
  1383.         }
  1384.  
  1385.     if ( (mster < DEMONLORD) && (mster != PLATINUMDRAGON) ) 
  1386.         if (c[CHARMCOUNT]) 
  1387.             if (rnd(30)+5*monster[mster].level-c[CHARISMA]<30) {
  1388.     lprintf("\nThe %s is awestruck at your magnificence!",lastmonst);
  1389.                 return;
  1390.             }
  1391.  
  1392.     if (mster==LEMMING) return;
  1393.     else {
  1394.         dam = monster[mster].damage;
  1395.         dam += rnd( (int) ((dam<1)?1:dam) ) + monster[mster].level;
  1396.     }
  1397.  
  1398.     /* demon lords/prince/god of hellfire damage is reduced if wielding
  1399.             Slayer */
  1400.     if (mster >= DEMONLORD)
  1401.         if (iven[c[WIELD]]==OSLAYER)
  1402.             dam=(int) (1 - (0.1 * rnd(5)) * dam);
  1403.  
  1404.     /*    spirit naga's and poltergeist's damage is halved if scarab of 
  1405.           negate spirit    */
  1406.     if (c[NEGATESPIRIT] || c[SPIRITPRO])  
  1407.         if ((mster ==POLTERGEIST) || (mster ==SPIRITNAGA)) 
  1408.             dam = (int) dam/2; 
  1409.  
  1410.     /*    halved if undead and cube of undead control    */
  1411.     if (c[CUBEofUNDEAD] || c[UNDEADPRO]) 
  1412.         if ((mster ==VAMPIRE) || (mster ==WRAITH) || (mster ==ZOMBIE)) 
  1413.             dam = (int) dam/2;
  1414.  
  1415.     tmp = 0;
  1416.     if (monster[mster].attack>0)
  1417.         if (((dam + bias + 8) > c[AC]) 
  1418.              || (rnd((int)((c[AC]>0)?c[AC]:1))==1)) {     
  1419.             if (spattack(monster[mster].attack,x,y)) {     
  1420.                 flushall(); 
  1421.                 return; 
  1422.             }
  1423.             tmp = 1;  
  1424.             bias -= 2; 
  1425.             cursors(); 
  1426.         }
  1427.  
  1428.     if (((dam + bias) > c[AC]) || (rnd((int)((c[AC]>0)?c[AC]:1))==1)) {
  1429.         lprintf("\n  The %s hit you ",lastmonst);    
  1430.         tmp = 1;
  1431.         if ((dam -= c[AC]) < 0) 
  1432.             dam=0;
  1433.  
  1434.         if (dam > 0) { 
  1435.             losehp(dam); 
  1436.             bottomhp(); 
  1437.             flushall(); 
  1438.         }
  1439.     }
  1440.  
  1441.     if (tmp == 0)  
  1442.         lprintf("\n  The %s missed ",lastmonst);
  1443. }
  1444.  
  1445. /*
  1446.  *    dropsomething(monst)     Function to create an object when a monster dies
  1447.  *        int monst;
  1448.  *
  1449.  *    Function to create an object near the player when 
  1450.  *    certain monsters are killed
  1451.  *    Enter with the monster number 
  1452.  *    Returns nothing of value.
  1453.  */
  1454. dropsomething(monst)
  1455. int monst;
  1456. {
  1457.     switch(monst) {
  1458.     case ORC:  
  1459.     case NYMPH:
  1460.     case ELF:
  1461.     case TROGLODYTE:
  1462.     case TROLL:
  1463.     case ROTHE:
  1464.     case VIOLETFUNGI:
  1465.     case PLATINUMDRAGON:
  1466.     case GNOMEKING:
  1467.     case REDDRAGON:
  1468.         something(level); 
  1469.         return;
  1470.  
  1471.     case LEPRECHAUN: 
  1472.         if (rnd(101)>=75) creategem();
  1473.         if (rnd(5)==1) dropsomething(LEPRECHAUN);   
  1474.         return;
  1475.     case LEMMING:    /* createitem(OGOLDPILE,1); */
  1476.         return;
  1477.     }
  1478. }
  1479.  
  1480. /*
  1481.  *    dropgold(amount)     Function to drop some gold around player
  1482.  *        int amount;
  1483.  *
  1484.  *    Enter with the number of gold pieces to drop
  1485.  *    Returns nothing of value.
  1486.  */
  1487. dropgold(amount)
  1488. register int amount;
  1489. {
  1490.     if (amount > 250) createitem(OMAXGOLD, amount);  
  1491.     else  createitem(OGOLDPILE,amount);
  1492. }
  1493.  
  1494. /*
  1495.  *    something(level)     Function to create a random item around player
  1496.  *        int level;
  1497.  *
  1498.  *    Function to create an item from a designed probability around player
  1499.  *    Enter with the cave level on which something is to be dropped
  1500.  *    Returns nothing of value.
  1501.  */
  1502. something(lev)
  1503. int lev;
  1504. {
  1505.     register int j;
  1506.     int i;
  1507.  
  1508.     if (lev<0 || lev>MAXLEVEL+MAXVLEVEL) 
  1509.         return;    /* correct level? */
  1510.     if (rnd(101)<8) 
  1511.         something(lev); /* possibly more than one item */
  1512.     j = newobject(lev,&i);        
  1513.     createitem(j,i);
  1514. }
  1515.  
  1516. /*
  1517.  *    newobject(lev,i)     Routine to return a randomly selected new object
  1518.  *        int lev,*i;
  1519.  *
  1520.  *    Routine to return a randomly selected object to be created
  1521.  *    Returns the object number created, and sets *i for its argument
  1522.  *    Enter with the cave level and a pointer to the items arg
  1523.  */
  1524. static char nobjtab[] = 
  1525.     0, OSCROLL,  OSCROLL,  OSCROLL,  OSCROLL, OPOTION,
  1526.     OPOTION, OPOTION, OPOTION, OGOLDPILE, OGOLDPILE, OGOLDPILE, OGOLDPILE, 
  1527.     OBOOK, OBOOK, OBOOK, OBOOK, ODAGGER, ODAGGER, ODAGGER, OLEATHER, OLEATHER,
  1528.     OLEATHER, OREGENRING, OPROTRING, OENERGYRING, ODEXRING, OSTRRING, OSPEAR,
  1529.     OBELT, ORING, OSTUDLEATHER, OSHIELD, OFLAIL, OCHAIN, O2SWORD, OPLATE,
  1530.     OLONGSWORD };
  1531.  
  1532. newobject(lev,i)
  1533. register int lev,*i;
  1534. {
  1535.     register int tmp=32,j;
  1536.  
  1537.     if (level<0 || level>MAXLEVEL+MAXVLEVEL) 
  1538.         return(0);    /* correct level? */
  1539.  
  1540.     if (lev>6) tmp=37; 
  1541.     else if (lev>4) tmp=35; 
  1542.  
  1543.     j = nobjtab[tmp=rnd(tmp)];    /* the object type */
  1544.     switch(tmp) {
  1545.     case 1: 
  1546.     case 2: 
  1547.     case 3: 
  1548.     case 4:    
  1549.         *i=newscroll();    
  1550.         break;
  1551.     case 5: 
  1552.     case 6: 
  1553.     case 7: 
  1554.     case 8:    
  1555.         *i=newpotion();    
  1556.         break;
  1557.     case 9: 
  1558.     case 10: 
  1559.     case 11: 
  1560.     case 12: 
  1561.         *i=rnd((lev+1)*10)+lev*10+10; 
  1562.         break;
  1563.     case 13: 
  1564.     case 14: 
  1565.     case 15:
  1566.     case 16:
  1567.         *i=lev;    
  1568.         break;
  1569.     case 17: 
  1570.     case 18: 
  1571.     case 19: 
  1572.         if (!(*i=newdagger()))  return(0);  
  1573.         break;
  1574.     case 20: 
  1575.     case 21: 
  1576.     case 22: 
  1577.         if (!(*i=newleather()))  return(0);  
  1578.         break;
  1579.     case 23: 
  1580.     case 32: 
  1581.     case 35: 
  1582.         *i=rund(lev/3+1); 
  1583.         break;
  1584.     case 24: 
  1585.     case 26: 
  1586.         *i=rnd(lev/4+1);   
  1587.         break;
  1588.     case 25: 
  1589.         *i=rund(lev/4+1); 
  1590.         break;
  1591.     case 27: 
  1592.         *i=rnd(lev/2+1);   
  1593.         break;
  1594.     case 28: 
  1595.         *i=rund(lev/3+1); 
  1596.         if (*i==0) return(0); 
  1597.         break;
  1598.     case 29: 
  1599.     case 31: 
  1600.         *i=rund(lev/2+1); 
  1601.         if (*i==0) return(0); 
  1602.         break;
  1603.     case 30: 
  1604.     case 33: 
  1605.         *i=rund(lev/2+1);   
  1606.         break;
  1607.     case 34: 
  1608.         *i=newchain();       
  1609.         break;
  1610.     case 36: 
  1611.         *i=newplate();       
  1612.         break;
  1613.     case 37: 
  1614.         *i=newsword();        
  1615.         break; 
  1616.     }
  1617.     return(j);
  1618. }
  1619.  
  1620. /*
  1621.  *            Function to process special attacks from monsters
  1622.  *  spattack(atckno,xx,yy)     
  1623.  *      int atckno,xx,yy;
  1624.  *
  1625.  *    Enter with the special attack number, and the coordinates (xx,yy)
  1626.  *        of the monster that is special attacking
  1627.  *    Returns 1 if must do a show1cell(xx,yy) upon return, 0 otherwise
  1628.  *
  1629.  * atckno   monster     effect
  1630.  * ---------------------------------------------------
  1631.  *    0    none
  1632.  *    1    rust monster        eat armor
  1633.  *    2    hell hound        breathe light fire
  1634.  *    3    dragon            breathe fire
  1635.  *    4    giant centipede        weakening sing
  1636.  *    5    white dragon        cold breath
  1637.  *    6    wraith            drain level
  1638.  *    7    waterlord        water gusher
  1639.  *    8    leprechaun        steal gold
  1640.  *    9    disenchantress        disenchant weapon or armor
  1641.  *    10    ice lizard        hits with barbed tail
  1642.  *    11    umber hulk        confusion
  1643.  *    12    spirit naga        cast spells taken from special attacks
  1644.  *    13    platinum dragon        psionics
  1645.  *    14    nymph            steal objects
  1646.  *    15    bugbear            bite
  1647.  *    16    osequip            bite
  1648.  *
  1649.  *    char rustarm[ARMORTYPES][2];
  1650.  *    special array for maximum rust damage to armor from rustmonster
  1651.  *    format is: { armor type , minimum attribute 
  1652.  */
  1653. #define ARMORTYPES 6
  1654.  
  1655. static char rustarm[ARMORTYPES][2] = 
  1656.     OSTUDLEATHER,-2,ORING,-4, OCHAIN,-5, OSPLINT,-6,OPLATE,-8,OPLATEARMOR,-9  };
  1657.  
  1658. static char spsel[] = { 
  1659.     1, 2, 3, 5, 6, 8, 9, 11, 13, 14 };
  1660. spattack(x,xx,yy)
  1661. int x,xx,yy;
  1662. {
  1663.     register int i,j=0,k,m;
  1664.     register char *p=0;
  1665.  
  1666.     vxy(&xx,&yy);    /* verify x & y coordinates */
  1667.  
  1668.     /* cancel only works 5% of time for demon prince
  1669.            and god */
  1670.     if (c[CANCELLATION]) 
  1671.         if (mitem[xx][yy] >= DEMONPRINCE) {
  1672.             if (rnd(100) >= 95) return(0);
  1673.         }
  1674.         else return(0);
  1675.  
  1676.     /* staff of power cancels demonlords/wraiths/vampires 75% of time */
  1677.     if (mitem[xx][yy] != LUCIFER) {
  1678.         if ( (mitem[xx][yy] >= DEMONLORD) ||
  1679.             (mitem[xx][yy] == WRAITH) ||
  1680.             (mitem[xx][yy] == VAMPIRE) )
  1681.             for (i=0;i<26;i++)
  1682.                 if (iven[i]==OPSTAFF) 
  1683.                     if (rnd(100)<75)
  1684.                         return(0);
  1685.     }
  1686.  
  1687.     /* if have cube of undead control,  wraiths and vampires do nothing */    
  1688.     if ( (mitem[xx][yy]==WRAITH) || (mitem[xx][yy]==VAMPIRE) )
  1689.         if ( (c[CUBEofUNDEAD]) || (c[UNDEADPRO]) )
  1690.             return(0);
  1691.  
  1692.     switch(x) {
  1693.     case 1:    /* rust your armor, j=1 when rusting has occurred */
  1694.         m = k = c[WEAR];
  1695.         if ((i=c[SHIELD]) != -1)
  1696.             if (--ivenarg[i] < -1) 
  1697.                 ivenarg[i]= -1; 
  1698.             else j=1;
  1699.         if ((j==0) && (k != -1)) {
  1700.             m = iven[k];
  1701.             for (i=0; i<ARMORTYPES; i++)
  1702.                 if (m == rustarm[i][0]) 
  1703.                     /* find his armor in table */
  1704.                 {
  1705.                     if (--ivenarg[k]< rustarm[i][1])
  1706.                         ivenarg[k]= rustarm[i][1]; 
  1707.                     else j=1; 
  1708.                     break;
  1709.                 }
  1710.         }
  1711.         if (j==0)    /* if rusting did not occur */
  1712.             switch(m) {
  1713.             case OLEATHER:    
  1714.                 p = "\nThe %s hit you -- You are lucky you have leather on";
  1715.                 break;
  1716.             case OSSPLATE:    
  1717.                 p = "\nThe %s hit you -- You are fortunate to have stainless steel armor!";
  1718.                 break;
  1719.             case OELVENCHAIN:
  1720.                 p = "\nThe %s hit you -- You are very lucky to have such strong elven chain!";
  1721.                 break;
  1722.             }
  1723.         else  { 
  1724.             beep(); 
  1725.             p = "\nThe %s hit you -- your armor feels weaker"; 
  1726.         }
  1727.         break;
  1728.  
  1729.     case 2:        
  1730.         i = rnd(15)+8-c[AC];
  1731. spout:    
  1732.         p="\nThe %s breathes fire at you!";
  1733.         if (c[FIRERESISTANCE])
  1734.             p="\nThe %s's flame doesn't phase you!";
  1735.         else
  1736. spout2: 
  1737.             if (p) { 
  1738.                 lprintf(p,lastmonst); 
  1739.                 beep(); 
  1740.             }
  1741.         checkloss(i);
  1742.         return(0);
  1743.  
  1744.     case 3:        
  1745.         i = rnd(20)+25-c[AC];  
  1746.         goto spout;
  1747.  
  1748.     case 4:    
  1749.         if (c[STRENGTH]>3) {
  1750.             p="\nThe %s stung you!  You feel weaker"; 
  1751.             beep();
  1752.             if (--c[STRENGTH] < 3)
  1753.                 c[STRENGTH] = 3;
  1754.         }
  1755.         else p="\nThe %s stung you!";
  1756.         break;
  1757.  
  1758.     case 5:        
  1759.         p="\nThe %s blasts you with his cold breath";
  1760.         i = rnd(15)+18-c[AC];  
  1761.         goto spout2;
  1762.  
  1763.     case 6:        
  1764.         lprintf("\nThe %s drains you of your life energy!",lastmonst);
  1765.         loselevel();
  1766.         if (mitem[xx][yy]==DEMONPRINCE) losemspells(1);
  1767.         if (mitem[xx][yy]==LUCIFER) {
  1768.             loselevel();
  1769.             losemspells(2);
  1770.             for (i=0;i<=5;i++) 
  1771.                 if (c[i]-- < 3) c[i]=3;
  1772.         }
  1773.         beep();  
  1774.         return(0);
  1775.  
  1776.     case 7:        
  1777.         p="\nThe %s got you with a gusher!";
  1778.         i = rnd(15)+25-c[AC];  
  1779.         goto spout2;
  1780.  
  1781.     case 8:    
  1782.         if (c[NOTHEFT]) return(0); 
  1783.         /* he has a device of no theft */
  1784.         if (c[GOLD]) {
  1785.             p="\nThe %s hit you -- Your purse feels lighter";
  1786.             if (c[GOLD]>32767)  c[GOLD]>>=1;
  1787.             else c[GOLD] -= rnd((int)(1+(c[GOLD]>>1)));
  1788.             if (c[GOLD] < 0) c[GOLD]=0;
  1789.         }
  1790.         else  p="\nThe %s couldn't find any gold to steal";
  1791.         lprintf(p,lastmonst); 
  1792.         disappear(xx,yy); 
  1793.         beep();
  1794.         bottomgold();  
  1795.         return(1);
  1796.  
  1797.     case 9:    
  1798.         for(j=50; ; )    /* disenchant */
  1799.         {
  1800.             i=rund(26);  
  1801.             m=iven[i]; /* randomly select item */
  1802.             if (m>0 && ivenarg[i]>0 && m!=OSCROLL && m!=OPOTION)
  1803.             {
  1804.                 if ((ivenarg[i] -= 3)<0) ivenarg[i]=0;
  1805.                 lprintf("\nThe %s hits you with a spell of disenchantment! ",lastmonst);
  1806.                 srcount=0; 
  1807.                 beep(); 
  1808.                 show3(i);  
  1809.                 bottomline();  
  1810.                 return(0);
  1811.             }
  1812.             if (--j<=0) {     
  1813.                 p="\nThe %s nearly misses"; 
  1814.                 break;
  1815.             }
  1816.             break;
  1817.         }        
  1818.         break;
  1819.  
  1820.     case 10:   
  1821.         p="\nThe %s hit you with his barbed tail";
  1822.         i = rnd(25)-c[AC];  
  1823.         goto spout2;
  1824.  
  1825.     case 11:
  1826.         p="\nThe %s has confused you"; 
  1827.         beep();
  1828.         c[CONFUSE]+= 10+rnd(10);        
  1829.         break;
  1830.  
  1831.     case 12:/*performs any number of other special attacks    */
  1832.         return(spattack(spsel[rund(10)],xx,yy));
  1833.  
  1834.     case 13:    
  1835.         p="\nThe %s flattens you with his psionics!";
  1836.         i = rnd(15)+30-c[AC];  
  1837.         goto spout2;
  1838.  
  1839.     case 14:    
  1840.         if (c[NOTHEFT]) return(0); 
  1841.         /* he has device of no theft */
  1842.         if (emptyhanded()==1) {
  1843.             p="\nThe %s couldn't find anything to steal";
  1844.             break;
  1845.         }
  1846.         lprintf("\nThe %s picks your pocket and takes:",lastmonst);
  1847.         beep();
  1848.         if (stealsomething()==0) lprcat("  nothing"); 
  1849.         disappear(xx,yy);
  1850.         bottomline();  
  1851.         return(1);
  1852.  
  1853.     case 15:
  1854.         i= rnd(10)+ 5-c[AC];
  1855. spout3:    
  1856.         p="\nThe %s bit you!";
  1857.         goto spout2;
  1858.  
  1859.     case 16:    
  1860.         i= rnd(15)+10-c[AC];  
  1861.         goto spout3;
  1862.     };
  1863.  
  1864.     if (p) { 
  1865.         lprintf(p,lastmonst); 
  1866.         bottomline(); 
  1867.     }
  1868.     return(0);
  1869. }
  1870.  
  1871. /*
  1872.  *        Routine to subtract hp from user and flag bottomline display
  1873.  *    checkloss(x)     
  1874.  *        int x;
  1875.  *
  1876.  *    Enter with the number of hit points to lose
  1877.  *    Note: if x > c[HP] this routine could kill the player!
  1878.  */
  1879. checkloss(x)
  1880. int x;
  1881. {
  1882.     if (x>0) { 
  1883.         losehp(x);  
  1884.         bottomhp(); 
  1885.     }
  1886. }
  1887.  
  1888. /*
  1889.  *    Routine to annihilate all monsters around player (playerx,playery)
  1890.  *    annihilate()     
  1891.  *
  1892.  *    Gives player experience, but no dropped objects
  1893.  *    Returns the experience gained from all monsters killed
  1894.  */
  1895. annihilate()
  1896. {
  1897.     int i,j;
  1898.     register long k;
  1899.     register char *p;
  1900.  
  1901.     for (k=0, i=playerx-1; i<=playerx+1; i++)
  1902.         for (j=playery-1; j<=playery+1; j++)
  1903.             if (!vxy(&i,&j)) /* if not out of bounds */
  1904.                 if (*(p= &mitem[i][j]))    /* if a monster there */
  1905.                     if (*p<DEMONLORD) {
  1906.                         k += monster[*p].experience;    
  1907.                         *p=know[i][j]=0;
  1908.                     }
  1909.                     else {
  1910.                         lprintf("\nThe %s barely escapes being annihilated!",monster[*p].name);
  1911.                         hitp[i][j] = (hitp[i][j]>>1) + 1; 
  1912.                         /* lose half hit points*/
  1913.                     }
  1914.     if (k>0) {
  1915.         lprcat("\nYou hear loud screams of agony!");    
  1916.         raiseexperience((long)k);
  1917.     }
  1918.     return(k);
  1919. }
  1920.  
  1921. /*
  1922.  *        Function to create a new sphere of annihilation
  1923.  *    newsphere(x,y,dir,lifetime)  
  1924.  *        int x,y,dir,lifetime;
  1925.  *
  1926.  *    Enter with the coordinates of the sphere in x,y
  1927.  *      the direction (0-8 diroffx format) in dir, and the lifespan of the
  1928.  *      sphere in lifetime (in turns)
  1929.  *    Returns the number of spheres currently in existence
  1930.  */
  1931. newsphere(x,y,dir,life)
  1932. int x,y,dir,life;
  1933. {
  1934.     int m,i;
  1935.     struct sphere *sp;
  1936.  
  1937.     if (((sp=(struct sphere *)malloc(sizeof(struct sphere)))) == 0)
  1938.         return(c[SPHCAST]);    /* can't malloc, therefore failure */
  1939.     if (dir>=9) dir=0;    /* no movement if direction not found */
  1940.     if (level==0) vxy(&x,&y);    /* don't go out of bounds */
  1941.     else {
  1942.         if (x<1) x=1;  
  1943.         if (x>=MAXX-1) x=MAXX-2;
  1944.         if (y<1) y=1;  
  1945.         if (y>=MAXY-1) y=MAXY-2;
  1946.     }
  1947.  
  1948.     for (i=0;i<26;i++) 
  1949.         if (iven[i]==OSPHTALISMAN) goto out;
  1950.  
  1951.     /* demons dispel spheres */
  1952.     if ((m=mitem[x][y]) >= DEMONLORD) {
  1953.         i = hitp[x][y];
  1954.         know[x][y]=1; 
  1955.         show1cell(x,y);    /* show the demon (ha ha) */
  1956.         cursors(); 
  1957.         lprintf("\nThe %s dispels the sphere!",monster[m].name);
  1958.         beep(); 
  1959.         rmsphere(x,y);    /* remove any spheres that are here */
  1960.         mitem[x][y] = m;
  1961.         hitp[x][y] = i;
  1962.         know[x][y]=0; 
  1963.         return(c[SPHCAST]);
  1964.     }
  1965.  
  1966.     /* disenchantress cancels spheres */
  1967.     if (m==DISENCHANTRESS) {
  1968.         cursors(); 
  1969.         lprintf("\nThe %s causes cancellation of the sphere!",monster[m].name); 
  1970.         beep();
  1971.  
  1972. boom:        
  1973.         sphboom(x,y);    /* blow up stuff around sphere */
  1974.         rmsphere(x,y);    /* remove any spheres that are here */
  1975.         return(c[SPHCAST]);
  1976.     }
  1977.  
  1978.     /* cancellation cancels spheres */
  1979.     if (c[CANCELLATION]) {
  1980.         cursors();
  1981.         lprcat("\nAs the cancellation takes effect, you hear a great earth shaking blast!"); 
  1982.         beep();
  1983.         goto boom;
  1984.     }
  1985.     /* collision of sphere and player! */
  1986.     if (playerx==x && playery==y) {
  1987.         cursors();
  1988.         lprcat("\nYou have been enveloped by the zone of nothingness!\n");
  1989.         beep(); 
  1990.         rmsphere(x,y);    /* remove any spheres that are here */
  1991.         nap(4000);  
  1992.         died(258);
  1993.     }
  1994. out:
  1995.     /* collision of spheres detonates spheres */
  1996.     if (item[x][y]==OANNIHILATION) {
  1997.         cursors(); 
  1998.         lprcat("\nTwo spheres of annihilation collide! You hear a great earth shaking blast!"); 
  1999.         beep();
  2000.         rmsphere(x,y);
  2001.         goto boom;
  2002.     }
  2003.  
  2004.     item[x][y]=OANNIHILATION;  
  2005.     mitem[x][y]=0;  
  2006.     know[x][y]=1;
  2007.     show1cell(x,y);    /* show the new sphere */
  2008.     sp->x=x;  
  2009.     sp->y=y;  
  2010.     sp->lev=level;  
  2011.     sp->dir=dir;  
  2012.     sp->lifetime=life;  
  2013.     sp->p=0;
  2014.     if (spheres==0) spheres=sp;    /* if first node in the sphere list */
  2015.     else    /* add sphere to beginning of linked list */
  2016.     {
  2017.         sp->p = spheres;    
  2018.         spheres = sp;
  2019.     }
  2020.     return(++c[SPHCAST]);    /* one more sphere in the world */
  2021. }
  2022.  
  2023. /*
  2024.  *    rmsphere(x,y)    Function to delete a sphere of annihilation from list
  2025.  *        int x,y;
  2026.  *
  2027.  *    Enter with the coordinates of the sphere (on current level)
  2028.  *    Returns the number of spheres currently in existence
  2029.  */
  2030. rmsphere(x,y)
  2031. int x,y;
  2032. {
  2033.     register struct sphere *sp,*sp2=0;
  2034.  
  2035.     for (sp=spheres; sp; sp2=sp,sp=sp->p)
  2036.         if (level==sp->lev)    /* is sphere on this level? */
  2037.             if ((x==sp->x) && (y==sp->y))    
  2038.                 /* locate sphere at this location */
  2039.             {
  2040.                 item[x][y]= mitem[x][y]= 0;  
  2041.                 know[x][y]=1;
  2042.                 show1cell(x,y);    /* show the now missing sphere */
  2043.                 --c[SPHCAST];    
  2044.                 if (sp==spheres) { 
  2045.                     sp2=sp; 
  2046.                     spheres=sp->p; 
  2047.                     free((char*)sp2); 
  2048.                 }
  2049.                 else
  2050.                 { 
  2051.                     sp2->p = sp->p;  
  2052.                     free((char*)sp); 
  2053.                 }
  2054.                 break;
  2055.             }
  2056.     return(c[SPHCAST]);    /* return number of spheres in the world */
  2057. }
  2058.  
  2059. /*
  2060.  *    sphboom(x,y)    Function to perform the effects of a sphere detonation
  2061.  *        int x,y;
  2062.  *
  2063.  *    Enter with the coordinates of the blast, Returns no value
  2064.  */
  2065. sphboom(x,y)
  2066. int x,y;
  2067. {
  2068.     register int i,j,k;
  2069.  
  2070.     if (c[HOLDMONST]) c[HOLDMONST]=1;
  2071.     if (c[CANCELLATION]) c[CANCELLATION]=1;
  2072.     for (j=max(1,x-2); j<min(x+3,MAXX-1); j++)
  2073.         for (i=max(1,y-2); i<min(y+3,MAXY-1); i++)
  2074.         {
  2075.             item[j][i]=mitem[j][i]=0;
  2076.             show1cell(j,i);
  2077.             for (k=0;k<26;k++) if (iven[k]==OSPHTALISMAN) return;
  2078.             if (playerx==j && playery==i)
  2079.             {
  2080.                 cursors(); 
  2081.                 beep();
  2082.                 lprcat("\nYou were too close to the sphere!");
  2083.                 nap(3000);
  2084.                 died(283); /* player killed in explosion */
  2085.             }
  2086.         }
  2087. }
  2088.  
  2089. /*
  2090.  *        Function to ask for monster and genocide from game
  2091.  *    genmonst()        
  2092.  *
  2093.  *    This is done by setting a flag in the monster[] structure
  2094.  */
  2095. genmonst()
  2096. {
  2097.     register int i,j;
  2098.     cursors();  
  2099.     lprcat("\nGenocide what monster? ");
  2100.     for (i=0; (!isalpha(i)) && (i!=' '); i=getcharacter());
  2101.     lprc(i);
  2102.     for (j=0; j<MAXMONST; j++)    /* search for the monster type */
  2103.         if (monstnamelist[j]==i)    /* have we found it? */
  2104.             if (monster[j].genocided==0) {
  2105.                 monster[j].genocided=1;    /* genocided from game */
  2106.                 lprintf("  There will be no more %s's",monster[j].name);
  2107.                 /* now wipe out monsters on this level */
  2108.                 newcavelevel(level); 
  2109.                 draws(0,MAXX,0,MAXY); 
  2110.                 bot_linex();
  2111.                 return;
  2112.             }
  2113.     lprcat("  You sense failure!");
  2114. }
  2115.